package com.demo.spring.aop.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class DemoAspectB implements Ordered {

    private final String thisClassName = this.getClass().getSimpleName();

    @Override
    public int getOrder() {
        return 10;
    }

    @Pointcut("execution(* com.demo.spring.aop.service.impl.DemoServiceImpl.targetMethod(..))" +
            "|| execution(* com.demo.spring.aop.service.impl.DemoServiceImpl.targetMethodException(..))")
    public void pointcut() { }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        MethodSignature methodSignature = (MethodSignature)pjp.getSignature();

        String targetClass = pjp.getTarget().getClass().getSimpleName();
        String targetMethod = methodSignature.getMethod().getName();
        String[] parameterNames = methodSignature.getParameterNames();
        Object[] parameters = pjp.getArgs();

        log.info("in {}.around, before proceed, ",thisClassName);
        log.info("targetClass={}, targetMethod={}, parameterNames={}, parameters={}  ",targetClass,targetMethod,parameterNames,parameters);

        parameters[0] = parameters[0]+", param changed by aspect";

        Object returns = pjp.proceed(parameters);

        log.info("in {}.around, after proceed, returns={},  ",thisClassName,returns);

        return returns;
    }

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) throws Throwable {
        log.info("in {}.before, ",thisClassName);

    }

    @After("pointcut()")
    public void after(JoinPoint joinPoint) throws Throwable {
        log.info("in {}.after, ",thisClassName);

    }

    @AfterReturning(value="pointcut()",returning = "returning")
    public Object afterReturning(JoinPoint joinPoint,Object returning){
        log.info("in {}.afterReturning, returning={}",thisClassName,returning);

        return returning;
    }

    @AfterThrowing("pointcut()")
    public Object afterThrowing(JoinPoint joinPoint){
        log.info("in {}.afterThrowing, ",thisClassName);

        return false;
    }

}
